home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- cache.c
-
- This module manages the article information cache.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #include "glob.h"
- #include "cache.h"
- #include "dialog.h"
- #include "memutil.h"
- #include "text.h"
- #include "fileutil.h"
- #include "windutil.h"
- #include "resutil.h"
- #include "ic.h"
-
-
-
- #define kCacheResourceType 'ACCH'
- #define kCacheGroupArrayID 128
- #define kCacheArticleArrayID 129
- #define kCacheStringsBlockID 130
-
-
-
- typedef struct TGroupInfo {
- long offset; /* offset in strings block of group name */
- long numCached; /* number of cached articles in this group */
- } TGroupInfo;
-
- typedef struct TArticleInfo {
- long groupIndex; /* index in group info array, or -1 if entry not used */
- long number; /* article number */
- long subjectOffset; /* offset in strings block of subject string */
- long authorOffset; /* offset in strings block of author string */
- unsigned long creationDateTime; /* date/time cache entry was created */
- } TArticleInfo;
-
-
- static Boolean gCacheDirty = false; /* true if cache changed since read from prefs file */
- static TGroupInfo **gGroupInfo = nil; /* handle to array of group info */
- static long gNumGroupInfo = 0; /* number of elements in group info array */
- static TArticleInfo **gArticleInfo = nil; /* handle to cached article info */
- static long gNumArticleInfo = 0; /* number of elements in article info array */
- static Handle gStrings = nil; /* handle to strings block */
- static long gStringsAllocated = 0; /* number of bytes allocated in strings block */
- static long gStringsUsed = 0; /* number of bytes used in strings block */
-
-
-
- /*----------------------------------------------------------------------------
- ValidCache
-
- Validate the cache.
-
- Exit: function result = true if no error.
- ----------------------------------------------------------------------------*/
-
- static Boolean ValidCache (void)
- {
- long i, j, numCached;
- TArticleInfo *p;
- TGroupInfo *q;
- unsigned long nowDateTimePlus24Hours;
-
- GetDateTime(&nowDateTimePlus24Hours);
- nowDateTimePlus24Hours += 24L*60L*60L;
-
- if (MyGetHandleSize(gGroupInfo) != gNumGroupInfo*sizeof(TGroupInfo)) goto exit;
- for (i = 0, q = *gGroupInfo; i < gNumGroupInfo; i++, q++) {
- if (q->offset < 0) goto exit;
- if (q->offset >= gStringsUsed) goto exit;
- if (strlen(*gStrings + q->offset) > 255) goto exit;
- numCached = 0;
- for (j = 0, p = *gArticleInfo; j < gNumArticleInfo; j++, p++)
- if (p->groupIndex == i) numCached++;
- if (numCached != q->numCached) goto exit;
- }
-
- if (MyGetHandleSize(gArticleInfo) != gNumArticleInfo*sizeof(TArticleInfo)) goto exit;
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex < 0) goto exit;
- if (p->groupIndex >= gNumGroupInfo) goto exit;
- if (p->number <= 0) goto exit;
- if (p->subjectOffset < 0) goto exit;
- if (p->subjectOffset >= gStringsUsed) goto exit;
- if (strlen(*gStrings + p->subjectOffset) > 255) goto exit;
- if (p->authorOffset < 0) goto exit;
- if (p->authorOffset >= gStringsUsed) goto exit;
- if (strlen(*gStrings + p->authorOffset) > 255) goto exit;
- if (p->creationDateTime > nowDateTimePlus24Hours) goto exit;
- }
-
- return true;
-
- exit:
-
- ErrorMessageNumber(kStrDamagedCache);
- return false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ReadArticleCache
-
- Read the article cache from the prefs file.
-
- Exit: function result = error code.
-
- This function must be called during initialization, when the prefs
- file is read.
- ----------------------------------------------------------------------------*/
-
- OSErr ReadArticleCache (void)
- {
- OSErr err = noErr;
-
- err = MyGet1Resource(kCacheResourceType, kCacheGroupArrayID, &gGroupInfo);
- if (err == resNotFound) {
- err = MyNewHandle(0, &gStrings);
- if (err != noErr) goto exit;
- err = MyNewHandle(0, &gGroupInfo);
- if (err != noErr) goto exit;
- err = MyNewHandle(0, &gArticleInfo);
- if (err != noErr) goto exit;
- } else if (err == noErr) {
- DetachResource((Handle)gGroupInfo);
- gNumGroupInfo = MyGetHandleSize(gGroupInfo) / sizeof(TGroupInfo);
- err = MyGet1Resource(kCacheResourceType, kCacheArticleArrayID, &gArticleInfo);
- if (err != noErr) goto exit;
- DetachResource((Handle)gArticleInfo);
- gNumArticleInfo = MyGetHandleSize(gArticleInfo) / sizeof(TArticleInfo);
- err = MyGet1Resource(kCacheResourceType, kCacheStringsBlockID, &gStrings);
- if (err != noErr) goto exit;
- DetachResource(gStrings);
- gStringsAllocated = gStringsUsed = MyGetHandleSize(gStrings);
- if (!ValidCache()) {
- FlushArticleCache();
- return userCanceledErr;
- }
- } else {
- goto exit;
- }
- return noErr;
-
- exit:
-
- MyDisposeHandle(gGroupInfo);
- MyDisposeHandle(gArticleInfo);
- MyDisposeHandle(gStrings);
- gGroupInfo = nil;
- gArticleInfo = nil;
- gStrings = nil;
- gNumGroupInfo = gNumArticleInfo = gStringsAllocated = gStringsUsed = 0;
- gCacheDirty = true;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CompactArticleCache
-
- Compact the cache.
- ----------------------------------------------------------------------------*/
-
- void CompactArticleCache (void)
- {
- TGroupInfo **groupInfo = nil, *q1, *q2;
- TArticleInfo **articleInfo = nil, *p1, *p2;
- Handle strings = nil;
- long numGroupInfo, numArticleInfo, stringsUsed, size, i, j, k;
- OSErr err = noErr;
- short sLen, aLen;
- unsigned long nowDateTimeMinus60Days;
-
- if (gGroupInfo == nil) return;
- GetDateTime(&nowDateTimeMinus60Days);
- nowDateTimeMinus60Days -= 60L*24L*60L*60L;
-
- MySetHandleSize(gStrings, gStringsUsed);
-
- size = MyGetHandleSize(gGroupInfo);
- err = MyNewHandle(size, &groupInfo);
- if (err != noErr) goto exit;
- numGroupInfo = 0;
-
- size = MyGetHandleSize(gArticleInfo);
- err = MyNewHandle(size, &articleInfo);
- if (err != noErr) goto exit;
- BlockMoveData(*gArticleInfo, *articleInfo, size);
- numArticleInfo = 0;
-
- size = MyGetHandleSize(gStrings);
- err = MyNewHandle(size, &strings);
- if (err != noErr) goto exit;
- stringsUsed = 0;
-
- for (i = 0, j = 0, q1 = *groupInfo, q2 = *gGroupInfo; j < gNumGroupInfo; j++, q2++) {
- if (q2->numCached > 0) {
- q1->offset = stringsUsed;
- q1->numCached = 0;
- strcpy(*strings + stringsUsed, *gStrings + q2->offset);
- stringsUsed += strlen(*strings + stringsUsed) + 1;
- numGroupInfo++;
- q1++;
- if (i != j) {
- for (k = 0, p1 = *articleInfo; k < gNumArticleInfo; k++, p1++)
- if (p1->groupIndex == j) p1->groupIndex = i;
- }
- i++;
- }
- }
- MySetHandleSize(groupInfo, numGroupInfo * sizeof(TGroupInfo));
-
- for (j = 0, p1 = *articleInfo, p2 = *articleInfo; j < gNumArticleInfo; j++, p2++) {
- if (p2->groupIndex >= 0 && p2->groupIndex < numGroupInfo &&
- p2->creationDateTime >= nowDateTimeMinus60Days)
- {
- sLen = strlen(*gStrings + p2->subjectOffset);
- aLen = strlen(*gStrings + p2->authorOffset);
- p1->groupIndex = p2->groupIndex;
- p1->number = p2->number;
- strcpy(*strings + stringsUsed, *gStrings + p2->subjectOffset);
- p1->subjectOffset = stringsUsed;
- stringsUsed += sLen + 1;
- strcpy(*strings + stringsUsed, *gStrings + p2->authorOffset);
- p1->authorOffset = stringsUsed;
- stringsUsed += aLen + 1;
- p1->creationDateTime = p2->creationDateTime;
- (*groupInfo)[p1->groupIndex].numCached++;
- numArticleInfo++;
- p1++;
- }
- }
- MySetHandleSize(articleInfo, numArticleInfo * sizeof(TArticleInfo));
-
- MySetHandleSize(strings, stringsUsed);
-
- MyDisposeHandle(gGroupInfo);
- gGroupInfo = groupInfo;
- gNumGroupInfo = numGroupInfo;
- MyDisposeHandle(gArticleInfo);
- gArticleInfo = articleInfo;
- gNumArticleInfo = numArticleInfo;
- MyDisposeHandle(gStrings);
- gStrings = strings;
- gStringsUsed = gStringsAllocated = stringsUsed;
-
- gCacheDirty = true;
-
- return;
-
- exit:
-
- MyDisposeHandle(strings);
- MyDisposeHandle(groupInfo);
- MyDisposeHandle(articleInfo);
- }
-
-
-
- /*----------------------------------------------------------------------------
- FlushArticleCache
-
- Flush the cache.
- ----------------------------------------------------------------------------*/
-
- void FlushArticleCache (void)
- {
- if (gGroupInfo == nil) return;
- MySetHandleSize(gGroupInfo, 0);
- gNumGroupInfo = 0;
- MySetHandleSize(gArticleInfo, 0);
- gNumArticleInfo = 0;
- MySetHandleSize(gStrings, 0);
- gStringsUsed = gStringsAllocated = 0;
- gCacheDirty = true;
- }
-
-
-
- /*----------------------------------------------------------------------------
- WriteArticleCache
-
- Write the article cache to the prefs file.
-
- Entry: newsServerAtStartup = news server name at startup.
-
- Exit: function result = error code.
-
- This function must be called during termination, when the prefs file
- is written.
- ----------------------------------------------------------------------------*/
-
- OSErr WriteArticleCache (Str255 newsServerAtStartup)
- {
- OSErr err = noErr;
-
- MyICReadSharedPrefs(kICNNTPHost);
-
- if (!gCacheDirty) return noErr;
-
- if (gGroupInfo == nil) {
- err = MyNewHandle(0, &gGroupInfo);
- if (err != noErr) return err;
- err = MyNewHandle(0, &gArticleInfo);
- if (err != noErr) return err;
- err = MyNewHandle(0, &gStrings);
- if (err != noErr) return err;
- } else if (!EqualString(gPrefs.newsServerName, newsServerAtStartup, false, true)) {
- FlushArticleCache();
- } else {
- CompactArticleCache();
- }
-
- /* Rewrite the three cache resources on the prefs file. */
-
- err = MyReplaceResource(gGroupInfo, kCacheResourceType, kCacheGroupArrayID, "\p");
- if (err != noErr) return err;
- err = MyReplaceResource(gArticleInfo, kCacheResourceType, kCacheArticleArrayID, "\p");
- if (err != noErr) return err;
- err = MyReplaceResource(gStrings, kCacheResourceType, kCacheStringsBlockID, "\p");
- if (err != noErr) return err;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AddCachedArticle
-
- Add an article to the cache.
-
- Entry: groupName = group name.
- number = article number.
- subject = subject.
- author = author.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr AddCachedArticle (char *groupName, long number, char *subject, char *author)
- {
- long i;
- TArticleInfo *p;
- TGroupInfo *q;
- long index = -1, groupIndex, subjectOffset, authorOffset, offset;
- OSErr err = noErr;
- short len, sLen, aLen;
-
- if (gGroupInfo == nil) return noErr;
-
- /* Check to see if this article is already in the cache.
- Also get index = index in article info array of a free entry, or
- -1 if none. */
-
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex >= 0) {
- if (number == p->number &&
- strcmp(groupName, *gStrings + (*gGroupInfo)[p->groupIndex].offset) == 0)
- return noErr;
- } else {
- index = i;
- }
- }
-
- /* If necessary, add the group name to the strings block and to the group info array. */
-
- for (groupIndex = 0, q = *gGroupInfo; groupIndex < gNumGroupInfo; groupIndex++, q++) {
- if (strcmp(groupName, *gStrings + q->offset) == 0) break;
- }
- if (groupIndex >= gNumGroupInfo) {
- len = strlen(groupName);
- if (gStringsUsed + len + 1 > gStringsAllocated) {
- err = MySetHandleSize(gStrings, gStringsAllocated+1000);
- if (err != noErr) return err;
- gStringsAllocated += 1000;
- }
- strcpy(*gStrings + gStringsUsed, groupName);
- offset = gStringsUsed;
- gStringsUsed += len+1;
- err = MySetHandleSize(gGroupInfo, (gNumGroupInfo+1) * sizeof(TGroupInfo));
- if (err != noErr) return err;
- groupIndex = gNumGroupInfo;
- q = &(*gGroupInfo)[groupIndex];
- q->offset = offset;
- q->numCached = 0;
- gNumGroupInfo++;
- }
-
- /* Add the subject and author strings to the strings block. */
-
- sLen = strlen(subject);
- aLen = strlen(author);
- if (gStringsUsed + sLen + aLen + 2 > gStringsAllocated) {
- err = MySetHandleSize(gStrings, gStringsAllocated+1000);
- if (err != noErr) return err;
- gStringsAllocated += 1000;
- }
- strcpy(*gStrings + gStringsUsed, subject);
- subjectOffset = gStringsUsed;
- gStringsUsed += sLen+1;
- len = strlen(author);
- strcpy(*gStrings + gStringsUsed, author);
- authorOffset = gStringsUsed;
- gStringsUsed += aLen+1;
-
- /* Add the new cache entry to the article info array. */
-
- if (index == -1) {
- err = MySetHandleSize(gArticleInfo, (gNumArticleInfo+1) * sizeof(TArticleInfo));
- if (err != noErr) return err;
- index = gNumArticleInfo;
- gNumArticleInfo++;
- }
- p = &(*gArticleInfo)[index];
- p->groupIndex = groupIndex;
- p->number = number;
- p->subjectOffset = subjectOffset;
- p->authorOffset = authorOffset;
- GetDateTime(&p->creationDateTime);
-
- /* Increment the counter in the group info array. */
-
- (*gGroupInfo)[groupIndex].numCached++;
-
- gCacheDirty = true;
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DeleteCachedArticle
-
- Remove an article from the cache.
-
- Entry: groupName = group name.
- number = article number.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DeleteCachedArticle (char *groupName, long number)
- {
- long groupIndex, i;
- TGroupInfo *q;
- TArticleInfo *p;
-
- if (gGroupInfo == nil) return noErr;
-
- for (groupIndex = 0, q = *gGroupInfo; groupIndex < gNumGroupInfo; groupIndex++, q++) {
- if (strcmp(groupName, *gStrings + q->offset) == 0) break;
- }
- if (groupIndex >= gNumGroupInfo) return noErr;
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex == groupIndex && p->number == number) {
- p->groupIndex = -1;
- (*gGroupInfo)[groupIndex].numCached--;
- gCacheDirty = true;
- return noErr;
- }
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CompareArticleNumbers
-
- Compare an article number to the article number in a TSubject record.
-
- Entry: *number = article number.
- x = pointer to TSubject record
-
- Exit: function result =
- -1 if article number < article number in TSubject record.
- 0 if article number = article number in TSubject record.
- +1 if article number > article number in TSubject record.
- ----------------------------------------------------------------------------*/
-
- static int CompareArticleNumbers (long *number, TSubject *x)
- {
- if (*number < x->number) {
- return -1;
- } else if (*number == x->number) {
- return 0;
- } else {
- return +1;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- AppendOneCachedArticle
-
- Append one cached article for a group to the end of a subject array.
-
- Entry: subjectArray = handle to subject array.
- oldNumSubjects = number of elements in original subject array.
- *numSubjects = current number of elements in subject array.
- strings = handle to strings block for subject window.
- number = article number.
- subjectOffset = offset of subject string in strings block.
- authorOffset = offset of author string in strings block.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr AppendOneCachedArticle (TSubject **subjectArray, short oldNumSubjects,
- short *numSubjects, Handle strings, long number, long subjectOffset,
- long authorOffset)
- {
- TSubject *x;
- OSErr err = noErr;
- long sOffset, aOffset;
- short sLen, aLen;
- char state;
-
- /* Check to see if this article was already read from the net. */
-
- state = MyHGetState(subjectArray);
- MyHLock(subjectArray);
- x = bsearch(&number, *subjectArray, oldNumSubjects, sizeof(TSubject),
- (int(*)(const void *, const void *))CompareArticleNumbers);
- MyHSetState(subjectArray, state);
- if (x != nil) return noErr;
-
- /* Check for too many subjects. */
-
- if (*numSubjects >= 16000) {
- ErrorMessageNumber(kStrTooManySubjects);
- return userCanceledErr;
- }
-
- /* Add the subject and author strings to the strings block for the
- subject window. */
-
- sLen = strlen(*gStrings + subjectOffset);
- aLen = strlen(*gStrings + authorOffset);
- sOffset = GetHandleSize(strings);
- aOffset = sOffset + sLen + 1;
- err = MySetHandleSize(strings, aOffset + aLen + 1);
- if (err != noErr) return err;
- strcpy(*strings + sOffset, *gStrings + subjectOffset);
- strcpy(*strings + aOffset, *gStrings + authorOffset);
-
- /* Add a new TSubject element to the end of the subject array. */
-
- err = MySetHandleSize(subjectArray, (*numSubjects+1)*sizeof(TSubject));
- if (err != noErr) return err;
- x = &(*subjectArray)[*numSubjects];
- x->number = number;
- x->subjectOffset = sOffset;
- x->authorOffset = aOffset;
- x->read = true;
- x->collapsed = gPrefs.showThreadsCollapsed;
- x->inList = true;
- x->drawTriangleFilled = false;
- x->onlyRedrawTriangle = false;
- x->onlyRedrawCheck = false;
- (*numSubjects)++;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AppendCachedArticles
-
- Append all the cached articles for a group to the end of the subject
- array for a subject window.
-
- Entry: wind = pointer to subject window.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr AppendCachedArticles (WindowPtr wind)
- {
- TWindow **info;
- CStr255 groupName;
- TSubject **subjectArray;
- short numSubjects, oldNumSubjects;
- long groupIndex, i;
- TGroupInfo *q;
- TArticleInfo *p;
- Handle strings;
- OSErr err = noErr;
-
- if (gGroupInfo == nil) return noErr;
-
- info = (TWindow**)GetWRefCon(wind);
- strcpy(groupName, *gGroupNames + (**info).groupNameOffset);
- subjectArray = (**info).subjectArray;
- numSubjects = oldNumSubjects = (**info).numSubjects;
- strings = (**info).strings;
-
- for (groupIndex = 0, q = *gGroupInfo; groupIndex < gNumGroupInfo; groupIndex++, q++) {
- if (strcmp(groupName, *gStrings + q->offset) == 0) break;
- }
- if (groupIndex >= gNumGroupInfo) return noErr;
-
- for (i = 0; i < gNumArticleInfo; i++) {
- p = &(*gArticleInfo)[i];
- if (p->groupIndex == groupIndex) {
- err = AppendOneCachedArticle(subjectArray, oldNumSubjects,
- &numSubjects, strings, p->number, p->subjectOffset,
- p->authorOffset);
- if (err != noErr) return err;
- }
- }
-
- (**info).numSubjects = numSubjects;
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AgeArticleCache
-
- Age the cached articles for a group.
-
- Entry: groupName = group name.
- low = low article number for this group on the server.
-
- Exit: function result = error code.
-
- All cached articles for the group with article numbers less than
- the low article number are deleted.
- ----------------------------------------------------------------------------*/
-
- OSErr AgeArticleCache (char *groupName, long low)
- {
- long groupIndex, i;
- TGroupInfo *q;
- TArticleInfo *p;
-
- if (gGroupInfo == nil) return noErr;
-
- for (groupIndex = 0, q = *gGroupInfo; groupIndex < gNumGroupInfo; groupIndex++, q++) {
- if (strcmp(groupName, *gStrings + q->offset) == 0) break;
- }
- if (groupIndex >= gNumGroupInfo) return noErr;
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex == groupIndex && p->number < low) {
- p->groupIndex = -1;
- (*gGroupInfo)[groupIndex].numCached--;
- gCacheDirty = true;
- }
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DumpArticleCacheToFile
-
- Dump the cache to a text file in human readable format (development
- version only).
-
- Entry: fSpec = pointer to file spec.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- #ifdef kDevelopmentVersion
-
- OSErr DumpArticleCacheToFile (FSSpec *fSpec)
- {
- OSErr err = noErr;
- short refNum = 0;
- CStr255 msg;
- Str255 dateString, timeString;
- long len, numCache = 0;
- TArticleInfo *p;
- TGroupInfo *q;
- long i;
- char state1, state2, state3;
-
- state1 = MyHGetState(gArticleInfo);
- state2 = MyHGetState(gArticleInfo);
- state3 = MyHGetState(gStrings);
-
- if (gGroupInfo == nil) {
- ErrorMessage("There is no cache.");
- return userCanceledErr;
- }
-
- err = FSpOpenDF(fSpec, fsRdWrPerm, &refNum);
- if (err != noErr) goto exit;
-
- MyHLock(gArticleInfo);
- MyHLock(gGroupInfo);
- MyHLock(gStrings);
-
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex >= 0) numCache++;
- }
-
- for (i = 0, q = *gGroupInfo; i < gNumGroupInfo; i++, q++) {
- sprintf(msg, "%9ld cached articles from %s\r", q->numCached, *gStrings + q->offset);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- }
-
- sprintf(msg, "\r%9ld total articles in cache\r\r%9ld total bytes in cache\r\r",
- numCache, MyGetHandleSize(gGroupInfo) + MyGetHandleSize(gArticleInfo) +
- MyGetHandleSize(gStrings));
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
-
- for (i = 0, p = *gArticleInfo; i < gNumArticleInfo; i++, p++) {
- if (p->groupIndex >= 0) {
- sprintf(msg, "%ld\r %s:%ld\r", i,
- *gStrings + (*gGroupInfo)[p->groupIndex].offset,
- p->number);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- sprintf(msg, " %s\r", *gStrings + p->subjectOffset);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- sprintf(msg, " %s\r", *gStrings + p->authorOffset);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- IUDateString(p->creationDateTime, shortDate, dateString);
- IUTimeString(p->creationDateTime, false, timeString);
- p2cstr(dateString);
- p2cstr(timeString);
- sprintf(msg, " Created %s %s\r", dateString, timeString);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- } else {
- sprintf(msg, "%ld\r *** unused ***\r", i);
- len = strlen(msg);
- MyFSWriteNoCache(refNum, &len, msg, nil);
- }
- }
-
- MyHSetState(gArticleInfo, state1);
- MyHSetState(gGroupInfo, state2);
- MyHSetState(gStrings, state3);
-
- MyFSClose(refNum, nil);
- return noErr;
-
- exit:
-
- if (refNum != 0) MyFSClose(refNum, nil);
- MyHSetState(gArticleInfo, state1);
- MyHSetState(gGroupInfo, state2);
- MyHSetState(gStrings, state3);
- return err;
- }
-
- #endif
-
-
-
- /*----------------------------------------------------------------------------
- DisplayArticleCache
-
- Display the cache in a text window in human readable format (development
- version only).
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- #ifdef kDevelopmentVersion
-
- OSErr DisplayArticleCache (void)
- {
- FSSpec fSpec;
- OSErr err = noErr;
- Handle text = nil;
- short refNum = 0;
- long len;
- WindowPtr wind;
-
- err = CreateTemporaryFile(&fSpec, kNewsWatcherSignature, 'ttxt', 'TEXT');
- if (err != noErr) goto exit;
- err = DumpArticleCacheToFile(&fSpec);
- if (err != noErr) goto exit;
- err = FSpOpenDF(&fSpec, fsRdPerm, &refNum);
- if (err != noErr) goto exit;
- err = MyNewHandle(0x7fff, &text);
- if (err != noErr) goto exit;
- len = 0x7fff;
- MyHLock(text);
- err = FSRead(refNum, &len, *text);
- MyHUnlock(text);
- MySetHandleSize(text, len);
- MyFSClose(refNum, nil);
- err = MakeNewTextWindow("\pArticle Cache", 0, nil, text, &wind);
- if (err != noErr) goto exit;
- MyDisposeHandle(text);
- return noErr;
-
- exit:
-
- if (refNum != 0) MyFSClose(refNum, nil);
- MyDisposeHandle(text);
- return err;
- }
-
- #endif